package com.ala4.oxcafe.common.utils.id;

import com.ala4.oxcafe.common.utils.RandomUtil;
import com.ala4.oxcafe.common.utils.date.DateUtil;

import java.net.NetworkInterface;
import java.nio.ByteBuffer;
import java.util.Enumeration;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * MongoDB ID生成策略实现
 *
 * @author PING
 * @version 1.0.0
 * @date 2025/7/31 16:47
 */
public class ObjectId {

    private ObjectId() {
    }

    /**
     * 线程安全的下一个随机数,每次生成自增+1
     */
    private static final AtomicInteger NEXT_INC = new AtomicInteger(RandomUtil.randomInt());
    /**
     * 机器信息
     */
    private static final int MACHINE = getMachinePiece() | getProcessPiece();

    /**
     * 获取一个objectId用下划线分割
     *
     * @return objectId
     */
    public static String next() {
        return next(false);
    }

    /**
     * 获取一个objectId
     *
     * @param withHyphen 是否包含分隔符
     * @return objectId
     */
    public static String next(boolean withHyphen) {
        byte[] array = nextBytes();
        final StringBuilder buf = new StringBuilder(withHyphen ? 26 : 24);
        int t;
        for (int i = 0; i < array.length; i++) {
            if (withHyphen && i % 4 == 0 && i != 0) {
                buf.append("-");
            }
            t = array[i] & 0xff;
            if (t < 16) {
                buf.append('0');
            }
            buf.append(Integer.toHexString(t));

        }
        return buf.toString();
    }

    /**
     * 获取一个objectId的bytes表现形式
     *
     * @return objectId
     */
    public static byte[] nextBytes() {
        final ByteBuffer bb = ByteBuffer.wrap(new byte[12]);
        bb.putInt((int) DateUtil.currentSeconds());// 4位
        bb.putInt(MACHINE);// 4位
        bb.putInt(NEXT_INC.getAndIncrement());// 4位

        return bb.array();
    }


    // ----------------------------------------------------------------------------------------- Private method start

    /**
     * 获取机器码片段
     *
     * @return 机器码片段
     */
    private static int getMachinePiece() {
        // 机器码
        int machinePiece;
        try {
            StringBuilder netSb = new StringBuilder();
            // 返回机器所有的网络接口
            Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
            // 遍历网络接口
            while (e.hasMoreElements()) {
                NetworkInterface ni = e.nextElement();
                // 网络接口信息
                netSb.append(ni.toString());
            }
            // 保留后两位
            machinePiece = netSb.toString().hashCode() << 16;
        } catch (Throwable e) {
            // 出问题随机生成,保留后两位
            machinePiece = (RandomUtil.randomInt()) << 16;
        }
        return machinePiece;
    }

    /**
     * 获取进程码片段
     *
     * @return 进程码片段
     */
    private static int getProcessPiece() {
        // 进程码
        // 因为静态变量类加载可能相同,所以要获取进程ID + 加载对象的ID值
        final int processPiece;
        // 进程ID初始化
        int processId;
        try {
            processId = Pid.INSTANCE.get();
        } catch (Throwable t) {
            processId = RandomUtil.randomInt();
        }
        final ClassLoader loader = ObjectId.class.getClassLoader();
        // 返回对象哈希码,无论是否重写hashCode方法
        int loaderId = (loader != null) ? System.identityHashCode(loader) : 0;

        // 进程ID + 对象加载ID
        // 保留前2位
        final String processSb = Integer.toHexString(processId) + Integer.toHexString(loaderId);
        processPiece = processSb.hashCode() & 0xFFFF;

        return processPiece;
    }
    // ----------------------------------------------------------------------------------------- Private method end
}
